const { executeInEditMode, ccclass, property } = cc._decorator;

@ccclass
@executeInEditMode
export default class ReactCamera extends cc.Component {
    _cam: cc.Camera = null;
    @property(cc.Camera)
    get cam() {
        if (!this._cam) {
            this._cam = this.getComponent(cc.Camera) || this.addComponent(cc.Camera);
        }
        return this._cam;
    }
    @property(cc.Node)
    target: cc.Node = null;
    @property
    reactInUpdate = true;

    @property({
        serializable: true,
        visible: false
    })
    _world = false;
    @property
    get world() {
        return this._world;
    }
    set world(val) {
        this._world = val;
        this.onChanged();
    }

    @property
    effectPos = false;
    @property
    _effectPosScale = 1.0;
    @property({
        visible() {
            return this.effectPos;
        },
    })
    get effectPosScale() {
        return this._effectPosScale;
    }
    set effectPosScale(val) {
        this._effectPosScale = val;
        this.onChanged();
    }

    @property({
        visible() {
            return this.effectPos;
        }
    })
    offsetPos: cc.Vec2 = new cc.Vec2();


    @property
    effectSize = false;
    @property
    _effectSizeScale = 1.0;
    @property({
        visible() {
            return this.effectSize;
        },
    })
    get effectSizeScale() {
        return this._effectSizeScale;
    }
    set effectSizeScale(val) {
        this._effectSizeScale = val;
        this.onChanged();
    }

    @property({
        visible() {
            return this.effectSize;
        }
    })
    offsetSize: cc.Vec2 = new cc.Vec2();

    @property
    effectScale = false;
    @property
    _effectScaleScale = 1.0;
    @property({
        visible() {
            return this.effectScale;
        },
    })
    get effectScaleScale() {
        return this._effectScaleScale;
    }
    set effectScaleScale(val) {
        this._effectScaleScale = val;
        this.onChanged();
    }

    protected onLoad(): void {
        this.node.on("size-changed", this.onOrthoChanged, this);
        this.node.on("scale-changed", this.onOrthoChanged, this);

        if (this.target) {
            this.setTarget(this.target);
        }
    }
    onOrthoChanged() {
        this.cam.orthoSize = this.node.height / 2 * this.node.scale;
    }

    setTarget(target: cc.Node) {
        if (cc.isValid(this.target)) {
            this.target.off("position-changed", this.onChanged, this);
            this.target.off("active-in-hierarchy-changed", this.onChanged, this);
            this.target.off("size-changed", this.onChanged, this);
            this.target.off("scale-changed", this.onChanged, this);
        }

        this.target = target;
        if (cc.isValid(this.target)) {
            this.target.on("position-changed", this.onChanged, this);
            this.target.on("active-in-hierarchy-changed", this.onChanged, this);
            this.target.on("size-changed", this.onChanged, this);
            this.target.on("scale-changed", this.onChanged, this);
            this.onChanged();
        }
    }
    onChanged() {
        if (!this.target) {
            return;
        }
        if (this.effectPos) {
            let pos: cc.Vec2 = null;
            if (this._world) {
                pos = this.target.convertToWorldSpaceAR(cc.Vec2.ZERO);
                pos = this.node.parent.convertToNodeSpaceAR(pos);
            }
            else {
                pos = cc.v2(this.target.position);
            }

            // -100
            // -50

            // 50  30/2=15;
            // 50-15
            if (pos.x < this.node.x - this.node.width / 2) {
                this.node.x = ((pos.x + this.node.width / 2) + this.offsetPos.x) * this._effectPosScale;
            }
            else if (pos.x > this.node.x + this.node.width / 2) {
                this.node.x = ((pos.x - this.node.width / 2) + this.offsetPos.x) * this._effectPosScale;
            }
            if (pos.y < this.node.y - this.node.height / 2) {
                this.node.y = ((pos.y + this.node.height / 2) + this.offsetPos.y) * this._effectPosScale;
            }
            else if (pos.y > this.node.y + this.node.height / 2) {
                this.node.y = ((pos.y - this.node.height / 2) + this.offsetPos.y) * this._effectPosScale;
            }
        }
        if (this.effectSize) {
            this.node.width = this.target.width * this._effectSizeScale + this.offsetSize.x;
            this.node.height = this.target.height * this._effectSizeScale + this.offsetSize.y;
        }
        if (this.effectScale) {
            let deltaX = (this.target.scaleX - 1) * this._effectScaleScale;
            this.node.scaleX = 1 + deltaX;
            let deltaY = (this.target.scaleY - 1) * this._effectScaleScale;
            this.node.scaleY = 1 + deltaY;
        }
    }

    protected lateUpdate(dt: number): void {
        if (CC_EDITOR || this.reactInUpdate) {
            this.onChanged();
        }
    }
};